/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#include <cubefs/api/reflection.hpp>
#include <cubefs/core/api/api.hpp>
#include <cubefs/api/names.hpp>

#include <cubefs/api/tools/version.hpp>
#include <cubefs/api/reflection/type.hpp>

#define CUBEFS_SOURCE "cubefs/core/api-impl/reflection.cpp:" CUBEFS_AT

cubefs::api::CoreFactory* CORE_FACTORY;

cubefs::api::CoreFactory* GetCoreFactory() {
	return CORE_FACTORY;
}

namespace cubefs { namespace api {

BooleanValue* TYPED_TRUE;
BooleanValue* TYPED_FALSE;

CUBEFS_DEFINE_REFLECTION_TYPE(Typed, 		TypedImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(Type, 		TypeImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(Operation, 	OperationImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(Argument, 	ArgumentImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(TypeSystem, 	TypeSystemImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(CoreFactory, 	CoreFactoryImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(List, 		ListImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(Value, 		ValueImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(Number, 		NumberImpl);
CUBEFS_DEFINE_REFLECTION_TYPE(VoidValue, 	VoidValueImpl);


Type* GetTypedNumberType(Int type_hash_code) {
	switch (type_hash_code)
	{
	case TypeHash<Byte>::hash : 		return TypedNumberImpl<Byte>::MyType(); break;
	case TypeHash<UByte>::hash : 		return TypedNumberImpl<UByte>::MyType(); break;
	case TypeHash<Short>::hash : 		return TypedNumberImpl<Short>::MyType(); break;
	case TypeHash<UShort>::hash : 		return TypedNumberImpl<UShort>::MyType(); break;
	case TypeHash<Int>::hash : 			return TypedNumberImpl<Int>::MyType(); break;
	case TypeHash<UInt>::hash : 		return TypedNumberImpl<UInt>::MyType(); break;
	case TypeHash<Long>::hash : 		return TypedNumberImpl<Long>::MyType(); break;
	case TypeHash<BigInt>::hash : 		return TypedNumberImpl<BigInt>::MyType(); break;
	case TypeHash<float>::hash : 		return TypedNumberImpl<float>::MyType(); break;
	case TypeHash<double>::hash : 		return TypedNumberImpl<double>::MyType(); break;

	default: throw CubefsException(CUBEFS_SOURCE, "Unknown type hash code", type_hash_code);
	}
	return NULL;
}

Type* GetTypedValueType(Int type_hash_code) {
	switch (type_hash_code)
	{
	case TypeHash<bool>::hash : 		return TypedValueImpl<bool>::MyType(); break;
	case TypeHash<void*>::hash : 		return TypedValueImpl<void*>::MyType(); break;
	case TypeHash<const void*>::hash : 	return TypedValueImpl<const void*>::MyType(); break;
	case TypeHash<String>::hash : 		return TypedValueImpl<String>::MyType(); break;
	case TypeHash<StringRef>::hash : 	return TypedValueImpl<StringRef>::MyType(); break;
	case TypeHash<IDValue>::hash : 		return TypedValueImpl<IDValue>::MyType(); break;
	case TypeHash<Version>::hash : 		return TypedValueImpl<Version>::MyType(); break;

	default: throw CubefsException(CUBEFS_SOURCE, "Unknown type hash code", type_hash_code);
	}
	return NULL;
}

Type* GetArrayType(Int type_hash_code) {
	switch (type_hash_code)
	{
	case TypeHash<Byte>::hash : 		return ArrayImpl<Byte>::MyType(); break;

	default: throw CubefsException(CUBEFS_SOURCE, "Unknown type hash code", type_hash_code);
	}
	return NULL;
}

Type* GetTypedListType(Int size, Int type_hash_code) {
	if (size == -1)
	{
		switch (type_hash_code)
		{
		case TypeHash<Typed*>::hash : 		return TypedListImpl<Typed*>::MyType(); break;
		case TypeHash<Type*>::hash : 		return TypedListImpl<Type*>::MyType(); break;
		case TypeHash<BigInt>::hash : 		return TypedListImpl<BigInt>::MyType(); break;
		case TypeHash<StringValue*>::hash : return TypedListImpl<StringValue*>::MyType(); break;

		default: throw CubefsException(CUBEFS_SOURCE, "Unknown type hash code", type_hash_code);
		}
	}
	else if (size == StaticListSize)
	{
		switch (type_hash_code)
		{
		case TypeHash<Typed*>::hash : 		return TypedListImpl<Typed*, StaticListSize>::MyType(); break;
		default: throw CubefsException(CUBEFS_SOURCE, "Unknown type hash code", type_hash_code);
		}
	}
	else {
		throw CubefsException(CUBEFS_SOURCE, "Unknown list size", size);
	}

	return NULL;
}

void Typed::SetPeerNotifier(PeerNotifier notifier) {
	TypedImpl::SetPeerNotifier(notifier);
}

void Typed::SetPeerCleanup(PeerCleanup cleanup) {
	TypedImpl::SetPeerCleanup(cleanup);
}

void InitReflectionTypes()
{
	CORE_FACTORY = new CoreFactoryImpl();

	TypedImpl::InitType();
    TypeImpl::InitType();
    OperationImpl::InitType();
    ArgumentImpl::InitType();

    TypeSystemImpl::InitType();
    CoreFactoryImpl::InitType();

    ValueImpl::InitType();

    TypedValueImpl<bool>::InitType();
    TypedValueImpl<void*>::InitType();
    TypedValueImpl<const void*>::InitType();
    TypedValueImpl<IDValue>::InitType();
    TypedValueImpl<String>::InitType();
    TypedValueImpl<const String>::InitType();
    TypedValueImpl<StringRef>::InitType();
    TypedValueImpl<Version>::InitType();

    VoidValueImpl::InitType();

    ListImpl::InitType();

    ListOfTypesImpl::InitType();
    ListOfTypedImpl::InitType();
    ListOfBigIntImpl::InitType();
    StaticListOfTypedImpl::InitType();
    ListOfStringsImpl::InitType();

    ArrayImpl<Byte>::InitType();

    NumberImpl::InitType();

    TypedNumberImpl<Int>::InitType();
    TypedNumberImpl<UInt>::InitType();
    TypedNumberImpl<Byte>::InitType();
    TypedNumberImpl<UByte>::InitType();
    TypedNumberImpl<Short>::InitType();
    TypedNumberImpl<UShort>::InitType();
    TypedNumberImpl<Long>::InitType();
    TypedNumberImpl<float>::InitType();
    TypedNumberImpl<double>::InitType();
    TypedNumberImpl<BigInt>::InitType();



    TYPED_TRUE  = new TypedValueImpl<bool>(true);
    TYPED_TRUE->SetManaged(true);

    TYPED_FALSE = new TypedValueImpl<bool>(false);
    TYPED_FALSE->SetManaged(true);

    TypedImpl::InitOperations();
    TypeImpl::InitOperations();
    OperationImpl::InitOperations();
    ArgumentImpl::InitOperations();

    ListImpl::InitOperations();

    ListOfTypesImpl::InitOperations();

    ListOfTypedImpl::InitOperations();
    ListOfBigIntImpl::InitOperations();
    StaticListOfTypedImpl::InitOperations();

    ListOfStringsImpl::InitOperations();

    ArrayImpl<Byte>::InitOperations();

    NumberImpl::InitOperations();

    TypedNumberImpl<Int>::InitOperations();
    TypedNumberImpl<UInt>::InitOperations();
    TypedNumberImpl<Byte>::InitOperations();
    TypedNumberImpl<UByte>::InitOperations();
    TypedNumberImpl<Short>::InitOperations();
    TypedNumberImpl<UShort>::InitOperations();
    TypedNumberImpl<Long>::InitOperations();
    TypedNumberImpl<float>::InitOperations();
    TypedNumberImpl<double>::InitOperations();
    TypedNumberImpl<BigInt>::InitOperations();

    ValueImpl::InitOperations();

    TypedValueImpl<bool>::InitOperations();
    TypedValueImpl<IDValue>::InitOperations();
    TypedValueImpl<void*>::InitOperations();
    TypedValueImpl<const void*>::InitOperations();
    TypedValueImpl<String>::InitOperations();
    TypedValueImpl<const String>::InitOperations();
    TypedValueImpl<StringRef>::InitOperations();

    TypedValueImpl<Version>::InitOperations();

    VoidValueImpl::InitOperations();

    TypeSystemImpl::InitOperations();
    CoreFactoryImpl::InitOperations();
}

}}

namespace std {

ostream& operator<<(ostream& os, const cubefs::api::IDValue& id) {
	os<<id.str();
	return os;
}

}

#undef CUBEFS_SOURCE
